// Usage:  js <thisfile> # should run without error.

// Lots of one-liners that tell us about JavaScript.

// Don't use '=='.  Use '===' instead.
0 == '0' || ddt();
0 == '' || ddt();
'' != '0' || ddt();

0 !== '0' || ddt();


var x, y, z;
// Keys and attributes are the same.
x = {}; x.a = 1; x['a'] === 1 || ddt();

// Keys are always strings.
x = {}; x[1] = 2; x['1'] === 2 || ddt();

// Missing keys return undefined.
x = {}; x.a === undefined; x['a'] === x.a || ddt();

// Object has some predefined keys (see inheritance).
x = {}; x.constructor !== undefined;
x = {}; x.constructor === Object.prototype.constructor;

undefined === (function(){})() || ddt();
1 === (function(){ return 1;})() || ddt();

// Don't use 'function xxx(){ ... }'.
1 === hoist1(); function hoist1(){return 1;};
var hoist2 = function (){}; 2 === hoist2(); function hoist2(){return 1;};

// 'this' in JavaScript is loosely similar to 'self' in Python.
var returnThis = function(){ return this;};

// 'this' is object whose method we are calling.
x = {}; x.a = returnThis;  x.a() === x || ddt();
x = {}; x['a'] = returnThis;  x['a']() === x || ddt();

// There is a global object, the 'default' value for 'this'.
returnThis() || ddt();
x = 0; returnThis().x = 1; x === 1 || ddt();


// We can use 'apply' or 'call' to set 'this'.
x = {}; returnThis.apply(x) === x || ddt();
x = {}; returnThis.call(x) === x || ddt();


x=''; x.a = 1; x.a === undefined || ddt();
x=1; x.a = 1; x.a === undefined || ddt();

new Boolean() !== new Boolean();

x = 1; y = returnThis.apply(x); x !== y && Number(x) === Number(y)|| ddt();
x = 'hi'; returnThis.apply(x) !== x || ddt();

var g = function (a){arguments[0]=7; return a;};
g(0) === 7 || ddt();
g() === undefined || ddt();


var f = function(s){ return '{' + s + '}'; };
"abc".replace(/.*/g, f) === '{abc}{}' || ddt();

"a\n\nb".replace(/([a-z])*|\n/g, f) === '{a}{}\n{}\n{b}{}';
"a\n\nb".replace(/([a-z])+|\n/g, f) === '{a}{\n}{\n}{b}';

"a\na\n\nb".replace(/([a-z ]+|\n.)+|(\n\s*){2,}/g, f) === '{a\na}{\n\n}{b}';


Array.prototype.push === [].push || ddt();

Array.push !== [].push || ddt();

parseInt(3/2) === 1 || ddt();

var x = new String('a'); x.a = 3 ; x.a === 3 || ddt();

// Subscript access sets 'this'.
f = function(){
    return this.a;
};
x = [f]; x.a = 3; x[0]() === 3 || ddt();

'abc'.toString(1, 2, 3) === 'abc' || ddt();

f = function(){return function(){};}; f() !== f() || ddt();


// This seems to produce an arguments object.
F = function(){}; F.prototype = Object; (new F).length === 1 || ddt();

F = function(){}; x = new F(); x.toString === Object.prototype.toString || ddt;

x = {}.constructor.constructor; x.constructor === x || ddt();

f = function(){};  g = function(){};
!((new g) instanceof f) || ddt();
g.prototype = f.prototype;
(new g) instanceof f || ddt();


// Rhino book talks of 'primitive JavaScript value'
// and of Number, Boolean, String object.
x = Object(3);
typeof x === 'object' || ddt();
x !== 3 || ddt();
x + 0 === 3 || ddt();

x.a = 3;
x.a === 3 || ddt();

x = 3; x.a = 3;
x.a === undefined || ddt();


a = {}; b = {};
X = function(){}; X.prototype = a;
x = new X();
a.isPrototypeOf(x) || ddt();

X.prototype = b;
a.isPrototypeOf(x) || ddt();

a = undefined; b = {}; b.x = 1;
(a || b).x === 1 || ddt();

(function(){return this;}).apply().x = 12;
x === 12 || ddt();



[].push.apply([], undefined) === 0 || ddt();  // Seems to fail on IE.

// GOTCHA: Had written: a !== b || c;
// GOTCHA: Typed this.modules.hasOwnProperty[name].

// GOTCHA.  Typed 'var run' instead of 'm.run'.


// Both SM and Firebug provide clear() - but different properties.

// This is a syntax error - invalid label.
// eval("{'pk':4}")

/*

 call.call(console.log, console, 1,2,3);
 console.log.call(console, 1, 2, 3);
 console.log(1, 2, 3)

 // Yes, it's obvious !!!  Equivalent to the above.
 call.apply(call, [console.log, console, 1,2,3]);
 console.log.call(console, 1, 2, 3);

 */

// FF2
''.split(/\s/).length === 1 || ddt();
''.split(/\s/) == '' || ddt();
[] != [] || ddt();


var fn = function(){};
fn.apply(null, null);           // OK in FF2, FF3.
fn.apply(null, null);           // Error: Object expected in IE6.


'this#that#other'.split('#', 2)[1] === 'that' || ddt();

true + true === 2 || ddt();

for (key in undefined){ ddt();}
for (key in null){ ddt();}

x = (function(){return this;}).call(1);
x * x === 1 || ddt();
x !== 1 || ddt();
x.a = 1;
x.a === 1 || ddt();

var root = Object.prototype;
var alt = Object.prototype = {};
alt !== root || ddt();
root === Object.prototype || ddt();


['', undefined, null, ''].join('') === '' || ddt();
'' + undefined === 'undefined' || ddt();
'' + null === 'null' || ddt();

x = NaN; x !== x || ddt();

// Syntax gotcha.
[[1,2,3], [4, 5, 6] [7, 8, 9]][2] === undefined || ddt();

-1 % 5 === -1 || ddt();

[] != [] || ddt();
[1, 2] != [1, 2] || ddt();

x = []; for (i in 'abc') x.push(i); x == '0,1,2' || ddt(); // Tested on FF.

Array(1, 2, 3) == '1,2,3' || ddt();
Array(3) == ',,' || ddt();

// var ; // SyntaxError: missing variable name:

var a = {}, b= {};
// a instanceof b; // TypeError: invalid 'instanceof' operand b.

/[a-z]*/(undefined)  || ddt;    // It seems that arg is converted to string.